package com.newdream.annotation.util;

import com.newdream.annotation.annotation.NeedSetValue;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

/**
 * @ author: sanglei
 * @ date: 2019-02-13 14:12
 * @ description:
 */
@Component
public class BeanUtil implements ApplicationContextAware {
    private ApplicationContext applicationContext;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if(this.applicationContext == null)
        this.applicationContext = applicationContext;
    }

    public void setFieldValueForCollection(Collection col){
        Map<String,Object> cacheMap = new HashMap<>();
        Class<?> clazz = col.iterator().next().getClass();
        Field[] fields = clazz.getDeclaredFields();
        try {
            for (Field field : fields) {
                NeedSetValue sv = field.getAnnotation(NeedSetValue.class);
                if (sv == null) {
                    continue;
                }
                field.setAccessible(true);

                Class<?> beanClass = sv.beanClass();
                String methodName = sv.method();
                String paramName = sv.param();
                String targetName = sv.targetField();



                Object bean = applicationContext.getBean(beanClass);

                Method method = beanClass.getDeclaredMethod(methodName, clazz.getDeclaredField(paramName).getType());

                Field paramField = clazz.getDeclaredField(paramName);
                paramField.setAccessible(true);

                Field targetField;
                boolean needInnerField = !StringUtils.isEmpty(targetName);

                String keyPrefix = beanClass.getName()+"_"+methodName+"_"+targetName+"_";
                for(Object o:col){
                    Object paramValue = paramField.get(o);
                    if(null==paramValue){
                        continue;
                    }
                    Object needValue = null;
                    String key = keyPrefix + paramValue;
                    if(cacheMap.containsKey(key)) {
                        needValue = cacheMap.get(key);
                    }else{
                        Object value = method.invoke(bean, paramValue);
                        if(needInnerField && null!=value) {
                            targetField = value.getClass().getDeclaredField(targetName);
                            needValue = targetField.get(value);
                        }
                        cacheMap.put(key,needValue);
                    }
                    field.set(o,needValue);
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }


}
